﻿using System;
using System.Collections.Generic;
using System.Text;

namespace System.Text
{
    /// <summary>
    /// 十六进制字符串编码
    /// </summary>
    public class HexEncoding : Encoding
    {
        /// <summary>
        /// 编码时的字节分隔符，为null表示不添加分隔符。
        /// </summary>
        public char? Separator { get; set; } = null;
        /// <summary>
        /// 编码时是否转为大写字母
        /// </summary>
        public bool Uppercase { get; set; } = true;

        public override int GetByteCount(char[] chars, int index, int count)
        {
            if (chars == null || chars.Length == 0)
            {
                return 0;
            }
            var ccount = 0;
            for (int i = 0; i < count; i++)
            {
                var c = chars[index + i];
                if (c != ' ' && c != '-' && c != '\0')//这是字符是解码时支持的分隔符
                {//统计不为空的字符数量
                    ccount++;
                }
            }
            var bcount = Math.Ceiling(ccount / 2d);
            return (int)bcount;
        }

        public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
        {
            char[] temp = new char[2];
            var tempCount = 0;
            var bcount = GetByteCount(chars, charIndex, charCount);
            int bi = byteIndex + bcount - 1;
            for (int i = charCount - 1; i >= 0; i--)
            {
                var c = chars[charIndex + i];
                if (c != ' ' && c != '-' && c != '\0')//这是字符是解码时支持的分隔符
                {
                    if (tempCount == 0)
                    {
                        temp[1] = c;
                        tempCount = 1;
                    }
                    else if (true)
                    {
                        temp[0] = c;
                        tempCount = 2;
                    }
                    if (tempCount == 2)
                    {
                        tempCount = 0;
                        bytes[bi] = System.Convert.ToByte(new string(temp), 16);
                        bi--;
                    }
                }
                if (tempCount == 1)
                {//最后一个孤立的字符，左侧补零。
                    temp[0] = '0';
                    bytes[bi] = System.Convert.ToByte(new string(temp), 16);
                }
            }
            return bcount;
        }

        public override int GetCharCount(byte[] bytes, int index, int count)
        {
            var ccount = count * 2;
            if (Separator.HasValue)
            {
                if (count <= 1)
                {//没有或只有1个字节
                    return ccount;
                }
                else
                {
                    return ccount + (count - 1);//每字节多带一个分隔符
                }

            }
            else
            {
                return ccount;
            }
        }

        public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
        {
            int charCount = 0;
            for (int i = 0; i < byteCount; i++)
            {
                var b = bytes[byteIndex + i];
                var temp = System.Convert.ToString(b, 16);
                if (temp.Length < 2)
                {//不足两位的左侧补零
                    temp = "0" + temp;
                }
                if (this.Uppercase)
                {
                    temp = temp.ToUpper();
                }
                for (int j = 0; j < temp.Length; j++)
                {
                    chars[charIndex + charCount] = temp[j];
                    charCount++;
                }
                if (i != byteCount - 1 && this.Separator.HasValue)
                {//非最后一字节且有分隔符
                    chars[charIndex + charCount] = this.Separator.Value;
                    charCount++;
                }
            }
            return charCount;
        }

        public override int GetMaxByteCount(int charCount)
        {
            var bcount = Math.Ceiling(charCount / 2d);
            return (int)bcount;
        }

        public override int GetMaxCharCount(int byteCount)
        {
            return byteCount * 2;
        }
    }
}
